#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "MessageEnd.h"
#include "NamedElement.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class InteractionOperand;
class NamedElement;
class Namespace;

/// <summary>
/// Gate
/// A Gate is a MessageEnd which serves as a connection point for relating a Message
/// which has a MessageEnd (sendEvent / receiveEvent) outside an InteractionFragment
/// with another Message which has a MessageEnd (receiveEvent / sendEvent)  inside
/// that InteractionFragment.
/// </summary>
class UMLMODEL_EXPORT Gate : public NamedElement, public MessageEnd {

public: // Constructors and destructors
    explicit Gate(const QString& umlType="uml::Gate");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// isOutsideCF
    /// This query returns true if this Gate is attached to the boundary of a
    /// CombinedFragment, and its other end (if present)  is outside of the same
    /// CombinedFragment.
    /// </summary>
    virtual bool isOutsideCF() const;

    /// <summary>
    /// isInsideCF
    /// This query returns true if this Gate is attached to the boundary of a
    /// CombinedFragment, and its other end (if present) is inside of an
    /// InteractionOperator of the same CombinedFragment.
    /// </summary>
    virtual bool isInsideCF() const;

    /// <summary>
    /// isActual
    /// This query returns true value if this Gate is an actualGate of an
    /// InteractionUse.
    /// </summary>
    virtual bool isActual() const;

    /// <summary>
    /// isFormal
    /// This query returns true if this Gate is a formalGate of an Interaction.
    /// </summary>
    virtual bool isFormal() const;

    /// <summary>
    /// getName
    /// This query returns the name of the gate, either the explicit name (.name) or the
    /// constructed name ('out_" or 'in_' concatenated in front of .message.name) if the
    /// explicit name is not present.
    /// </summary>
    virtual QString getName() const;

    /// <summary>
    /// matches
    /// This query returns true if the name of this Gate matches the name of the in
    /// parameter Gate, and the messages for the two Gates correspond. The Message for
    /// one Gate (say A) corresponds to the Message for another Gate (say B) if (A and B
    /// have the same name value) and (if A is a sendEvent then B is a receiveEvent) and
    /// (if A is a receiveEvent then B is a sendEvent) and (A and B have the same
    /// messageSort value) and (A and B have the same signature value).
    /// </summary>
    virtual bool matches(shared_ptr<Gate> gateToMatch) const;

    /// <summary>
    /// isDistinguishableFrom
    /// The query isDistinguishableFrom() specifies that two Gates may coexist in the
    /// same Namespace, without an explicit name property. The association end
    /// formalGate subsets ownedElement, and since the Gate name attribute
    /// is
    /// optional, it is allowed to have two formal gates without an explicit name, but
    /// having derived names which are distinct.
    /// </summary>
    bool isDistinguishableFrom(shared_ptr<NamedElement> n, shared_ptr<Namespace> ns) const override;

    /// <summary>
    /// getOperand
    /// If the Gate is an inside Combined Fragment Gate, this operation returns the
    /// InteractionOperand that the opposite end of this Gate is included within.
    /// </summary>
    virtual shared_ptr<InteractionOperand> getOperand() const;

};

} // namespace uml
